package dal

import (
	"context"
	"fmt"

	commonTools "algo-sdk-go/common/tools"
	"algo-sdk-go/framework/middleware/db/mongodb/dbops"
	"algo-sdk-go/project/matchmaking/adapter/convertor"
	"algo-sdk-go/project/matchmaking/common/constant"
	"algo-sdk-go/project/matchmaking/domain/models/entity"
	"algo-sdk-go/project/matchmaking/domain/port/repo/ops"
	"algo-sdk-go/project/matchmaking/matchMaking-api/config"

	"github.com/pkg/errors"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type UserProfileDal struct {
	UserProfileCollection *mongo.Collection
}

func NewUserProfileRepository(config *config.Config) *UserProfileDal {
	mc, err := mongo.Connect(context.Background(), options.Client().ApplyURI(config.Mongo.Url))
	if err != nil {
		panic(err)
	}

	return &UserProfileDal{
		UserProfileCollection: mc.Database(config.Mongo.DataBase).Collection(constant.UserProfileDBName),
	}
}

func (u *UserProfileDal) Save(ctx context.Context, userProfile *entity.UserProfile) (int, error) {
	poInfo := convertor.ConvertUserProfileToPo(userProfile)
	if _, err := u.UserProfileCollection.InsertOne(ctx, poInfo); err != nil {
		return -1, err
	}
	return userProfile.UserNum, nil
}

func (u *UserProfileDal) Modify(ctx context.Context, userProfile *entity.UserProfile) error {
	userProfilePo := convertor.ConvertUserProfileToPo(userProfile)

	if err := dbops.Valid(ops.UserProfileValid(userProfilePo)); err != nil {
		return errors.WithMessage(err, "userProfilePo_valid_error")
	}

	filter := dbops.GetFilter(
		ops.WithUserNum(userProfile.UserNum, constant.DBUserNum),
	).AndOperator()

	updateInfo := dbops.GetUpdater(
		dbops.SetIntValue(constant.DBHeight, userProfile.Height),
		dbops.SetIntValue(constant.DBWeight, userProfile.Weight),
		dbops.SetValue(constant.DBUserAvatar, userProfile.UserAvatar),
	).Set()

	if _, err := u.UserProfileCollection.UpdateOne(ctx, filter, updateInfo); err != nil {
		return errors.Wrapf(err, "UserProfileDal Modify UpdateOne error, userProfilePo: %+v", userProfilePo)
	}
	return nil
}

func (u *UserProfileDal) LoadUserProfileByUserNums(ctx context.Context, userNumList []int) ([]entity.UserProfile, error) {
	if len(userNumList) == 0 {
		return nil, nil
	}

	filter := dbops.GetFilter(
		ops.WithUserNumsRemoveZero(userNumList, constant.DBUserNum),
	).AndOperator()
	return dbops.GetAllItemsFromMongo(ctx, u.UserProfileCollection, filter, nil, convertor.ConvertUserProfileToEntity)
}

func (u *UserProfileDal) CountUserProfileByCondition(ctx context.Context, condition ops.Condition) (int, error) {
	filter := LoadUserProfileFilter(condition)

	count, err := u.UserProfileCollection.CountDocuments(ctx, filter)
	if err != nil {
		return 0, errors.Wrapf(err, "CountUserProfileByCondition CountDocuments err, filter: %+v", filter)
	}

	return int(count), nil
}

func (u *UserProfileDal) LoadUserProfileByCondition(ctx context.Context, condition ops.Condition) ([]entity.UserProfile, error) {
	filter := LoadUserProfileFilter(condition)

	opts := dbops.GetOpts(
		dbops.SetSortBy(condition.SortBy, constant.DBUpdateTime),
		dbops.SetPageNumPageSize(condition.PageNum, condition.PageSize, condition.IgnorePage),
	).Get()

	fmt.Println("-----", commonTools.JsonToString(filter))

	return dbops.GetAllItemsFromMongo(ctx, u.UserProfileCollection, filter, opts, convertor.ConvertUserProfileToEntity)
}
